package com.yj.passport.service.impl;

import com.yj.cache.service.YjCacheService;
import com.yj.passport.constants.LoginOriginType;
import com.yj.passport.entity.UserPassport;
import com.yj.passport.service.PassportService;
import com.yj.passport.utils.TicketUtils;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


/**
 * 注意,手机端和web端实际用的都是同一张票（但是web端传输的是md5后的票），在redis里面存得key不一样。
 *
 * @author yesiming
 */
public class PassportServiceImpl implements PassportService {

    private static final Log logger = LogFactory.getLog(PassportServiceImpl.class);

    private YjCacheService passportCache;

    // 过期时间一个月
    private static final int WEB_LOGIN_EXPIRES = 2592000;

    private boolean destroyTicket(String ticket, int type) {
        boolean rt = false;
        if (StringUtils.isEmpty(ticket)) {
            return rt;
        }
        UserPassport userPassport = getPassportByTicket(ticket, type);
        if (userPassport != null) {
            long uid = TicketUtils.decryptTicket(ticket);
            if (uid <= 0) {
                return rt;
            }
            try {
                passportCache.del(key(uid, type));
                rt = !passportCache.exists(key(uid, type));
            } catch (Exception e) {
                logger.error("destoryTicket fail", e);
                rt = false;
            }
        }
        return rt;
    }

    private UserPassport getPassportByTicket(String ticket, int type) {
        UserPassport userPassport = null;
        if (StringUtils.isEmpty(ticket)) {
            return userPassport;
        }
        long uid = TicketUtils.decryptTicket(ticket);
        if (uid <= 0) {
            return userPassport;
        }
        try {
            userPassport = passportCache.get(key(uid, type), UserPassport.class);
            if (userPassport != null && !StringUtils.equals(userPassport.getTicket(), ticket)) {
//                logger.info(LogUtil.getLogTag() + "ticket is not equals");
                userPassport = null;
            }
        } catch (Exception e) {
            logger.error("getPassportByTicket fail", e);
        }
//        logger.info(LogUtil.getLogTag() + "userPassport is not null" + userPassport != null);
        return userPassport;
    }

    private String createTicket(UserPassport userPassport, int type, int seconds) {
        String ticket = null;
        if (userPassport == null || userPassport.getUserId() == 0) {
            return ticket;
        }
        ticket = TicketUtils.generateTicket(userPassport.getUserId());
        userPassport.setTicket(ticket);
        if (!StringUtils.isEmpty(ticket)) {
            try {
                passportCache.del(key(userPassport.getUserId(), type));
                if (seconds == 0) {
                    passportCache.set(key(userPassport.getUserId(), type), userPassport, UserPassport.class);
                } else {
                    passportCache.set(key(userPassport.getUserId(), type), userPassport, UserPassport.class, seconds);
                }
            } catch (Exception e) {
                logger.error("createTicket fail", e);
                ticket = null;
            }
        }
        return ticket;
    }

    private String getTicketByUserId(long userId, int type) {
        String ticket = null;
        UserPassport userPassport = null;
        if (userId != 0) {
            try {
                userPassport = passportCache.get(key(userId, type), UserPassport.class);
            } catch (Exception e) {
                logger.error("getTicketByUserId fail", e);
            }
            if (userPassport != null) {
                ticket = userPassport.getTicket();
                long uid = TicketUtils.decryptTicket(ticket);
                if (uid <= 0) {
                    return null;
                }
                if (uid != userId) {
                    return null;
                }
            }
        }
        return ticket;
    }

    private long getUserIdByTicket(String ticket, int type) {
        long userId = 0;
        UserPassport userPassport = getPassportByTicket(ticket, type);
        if (userPassport == null) {
            return userId;
        }
        userId = userPassport.getUserId();
        return userId;
    }

    @Override
    public long getUserIdByTicket4Mobile(String ticket) {
        return this.getUserIdByTicket(ticket, LoginOriginType.MOBILE);
    }

    @Override
    public boolean destroyTicket4Mobile(String ticket) {
        return this.destroyTicket(ticket, LoginOriginType.MOBILE);
    }

    @Override
    public UserPassport getPassportByTicket4Mobile(String ticket) {
        return this.getPassportByTicket(ticket, LoginOriginType.MOBILE);
    }

    @Override
    public String createTicket4Mobile(UserPassport userPassport) {
        return this.createTicket(userPassport, LoginOriginType.MOBILE, 0);
    }

    @Override
    public String getTicketByUserId4Mobile(long userId) {
        return this.getTicketByUserId(userId, LoginOriginType.MOBILE);
    }

    @Override
    public long getUserIdByTicket4Web(String pubTicket) {
        String ticket = null;
        try {
            ticket = this.passportCache.get(keyPubTicket(pubTicket), String.class);
        } catch (Exception e) {
            logger.error("getUserIdByTicket4Web fail", e);
        }
        return this.getUserIdByTicket(ticket, LoginOriginType.WEB);
    }

    @Override
    public boolean destroyTicket4Web(String pubTicket) {
        boolean rt = false;
        try {
            String ticket = this.passportCache.get(keyPubTicket(pubTicket), String.class);
            rt = this.destroyTicket(ticket, LoginOriginType.WEB);
            if (rt) {
                this.passportCache.del(keyPubTicket(pubTicket));
                rt = !passportCache.exists(keyPubTicket(pubTicket));
            }
        } catch (Exception e) {
            logger.error("destroyTicket4Web fail", e);
            rt = false;
        }
        return rt;
    }

    @Override
    public UserPassport getPassportByTicket4Web(String pubTicket) {
        String ticket = null;
        try {
            ticket = this.passportCache.get(keyPubTicket(pubTicket), String.class);
        } catch (Exception e) {
            logger.error("getPassportByTicket4Web fail", e);
        }
        return this.getPassportByTicket(ticket, LoginOriginType.WEB);
    }

    @Override
    public String createPubTicket4Web(UserPassport userPassport) {
        String pubTicket = null;
        try {
            String ticket = this.createTicket(userPassport, LoginOriginType.WEB, WEB_LOGIN_EXPIRES);
            if (StringUtils.isEmpty(ticket)) {
                return pubTicket;
            }
            pubTicket = DigestUtils.md5Hex(ticket);
            this.passportCache.del(keyPubTicket(pubTicket));
            this.passportCache.set(keyPubTicket(pubTicket), ticket, String.class, WEB_LOGIN_EXPIRES);
        } catch (Exception e) {
            logger.error("createPubTicket4Web fail", e);
            pubTicket = null;
        }
        return pubTicket;
    }

    @Override
    public String getTicketByUserId4Web(long userId) {
        return this.getTicketByUserId(userId, LoginOriginType.WEB);
    }

    @Override
    public String getPubTicketByUserId4Web(long userId) {
        String ticket = this.getTicketByUserId(userId, LoginOriginType.WEB);
        if (StringUtils.isEmpty(ticket)) {
            return ticket;
        }
        String pubTicket = DigestUtils.md5Hex(ticket);
        if (this.passportCache.exists(keyPubTicket(pubTicket))) {
            return pubTicket;
        } else {
            return null;
        }
    }

    private String key(long uid, int type) {
        if (type == LoginOriginType.MOBILE) {
            // type为0，是手机端的登陆
            return "yj.ms.pt." + uid;
        } else if (type == LoginOriginType.WEB) {
            // type为1，是web端的登陆
            return "yj.ms.pt.wb." + uid;
        } else {
            // 默认为手机端的登陆
            return "yj.ms.pt." + uid;
        }

    }

    private String keyPubTicket(String pubTicket) {
        return "yj.ms.pt.wb.pubt." + pubTicket;
    }

    public void setPassportCache(YjCacheService passportCache) {
        this.passportCache = passportCache;
    }

}
